//
// Created by zhoubigbo on 2017/12/18.
//

#include <unistd.h>
#include "player.h"

Player::Player(Audio *audio, Video *video) {
    this->audio = audio;
    this->video = video;
}

Player::~Player() {}

int Player::init(const char *input) {
    //1.注册
    av_register_all();
    //封装格式上下文
    fmtCtx = avformat_alloc_context();

    ret = avformat_open_input(&fmtCtx, input, NULL, NULL);

    if (ret != 0) {
        return OPEN_INPUT_ERR;
    }

    //3.获取视频信息
    ret = avformat_find_stream_info(fmtCtx, NULL);
    if (ret < 0) {
        return FIND_STREAM_ERR;
    }
    return 0;
}

int Player::open_codec() {

    for (int i = 0; i < fmtCtx->nb_streams; i++) {
        if (fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
            audio_stream_index = i;
            break;
        }
    }

    for (int i = 0; i < fmtCtx->nb_streams; i++) {
        if (fmtCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
            video_stream_index = i;
            break;
        }
    }

    video->codecCtx = fmtCtx->streams[video_stream_index]->codec;
    video->codec = avcodec_find_decoder(video->codecCtx->codec_id);
    if (video->codec == NULL) {
        return FIND_CODEC_ERR;
    }
    ret = avcodec_open2(video->codecCtx, video->codec, NULL);
    if (ret < 0) {
        return OPEN_CODEC_ERR;
    }

    audio->codecCtx = fmtCtx->streams[audio_stream_index]->codec;
    audio->codec = avcodec_find_decoder(audio->codecCtx->codec_id);
    if (audio->codec == NULL) {
        return FIND_CODEC_ERR;
    }
    ret = avcodec_open2(audio->codecCtx, audio->codec, NULL);
    if (ret != 0) {
        return OPEN_CODEC_ERR;
    }

    ret = avcodec_open2(video->codecCtx, video->codec, NULL);
    if (ret < 0) {
        return OPEN_CODEC_ERR;
    }
    return 0;
}

int Player::prepare_audio() {
    //输入的采样格式
    audio->in_sampleFormat = audio->codecCtx->sample_fmt;
    //输出的采样格式
    audio->out_sampleFormat = AV_SAMPLE_FMT_S16;
    //输入采样率
    audio->in_sample_rate = audio->codecCtx->sample_rate;
    //输出采样率
    audio->out_sample_rate = audio->in_sample_rate;
    //输入声道布局
    audio->in_ch_layout = audio->codecCtx->channel_layout;
    //输出声道布局
    audio->out_ch_layout = AV_CH_LAYOUT_STEREO;//立体声
    //输出声道个数
    audio->out_ch_no = av_get_channel_layout_nb_channels(audio->out_ch_layout);
    //获取视频压缩数据
    // audio->packet = (AVPacket *) av_malloc(sizeof(AVPacket));
    audio->swrCtx = swr_alloc();
    swr_alloc_set_opts(audio->swrCtx,
                       audio->out_ch_layout, audio->out_sampleFormat, audio->out_sample_rate,
                       audio->in_ch_layout, audio->in_sampleFormat, audio->in_sample_rate,
                       0, NULL);
    swr_init(audio->swrCtx);
    //16bit 44100 PCM 数据
    audio->out_buffer = (uint8_t *) av_malloc(48000 << 2);
    return 0;
}

int Player::prepare_video() {
    //编码数据
    // video->packet = (AVPacket *) av_malloc(sizeof(AVPacket));
    video->scale_frame = av_frame_alloc();
    return 0;
}

void Player::prepare_player() {
    //frame = av_frame_alloc();
    video->frame = av_frame_alloc();
    audio->frame = av_frame_alloc();
    packet = (AVPacket *) av_malloc(sizeof(AVPacket));
    prepare_video();
    prepare_audio();
    video_queue = new BlockingQueue<AVPacket>();
    audio_queue = new BlockingQueue<AVPacket>();
}

void Player::decode_audio_frame(void (*fp)(int)) {
    //解码
    AVPacket temp;
    while(isPlaying&&audio_queue->pop(temp)){
        if (temp.stream_index == audio_stream_index) {
            int got_frame = 0;
            ret = avcodec_decode_audio4(audio->codecCtx, audio->frame, &got_frame, &temp);
            if (ret < 0) {
                break;
            }
            //解码一帧成功
            if (got_frame > 0) {
                swr_convert(audio->swrCtx, &audio->out_buffer, 48000 * 4, (const uint8_t **) audio->frame->data,
                            audio->frame->nb_samples);
                //获取sample的size
                int out_buffer_size = av_samples_get_buffer_size(NULL, audio->out_ch_no,
                                                                 audio->frame->nb_samples, audio->out_sampleFormat, 1);
                fp(out_buffer_size);
            }
        }
    }
    isPlaying = false;
}

void Player::decode_video_frame(void (*fp)()) {
    //缓冲区分配合适内存
    AVPacket temp;
    while(isPlaying&&video_queue->pop(temp)){
        if (temp.stream_index == video_stream_index) {
            uint8_t *buf = (uint8_t *) av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, video->codecCtx->width, video->codecCtx->height));
            avpicture_fill((AVPicture *) video->scale_frame, buf, AV_PIX_FMT_YUV420P, video->codecCtx->width, video->codecCtx->height);
            int got_pic;
            avcodec_decode_video2(video->codecCtx, video->frame, &got_pic, &temp);
            if (got_pic) {//非零，表示可以进行解码操作
                fp();
            }
        }
    }
    isPlaying = false;
}

void Player::decode_frame(void (*fp)(int), void (*fpv)()) {
    isPlaying = true;
    while (av_read_frame(fmtCtx, packet) >= 0) {//从packet数据读取frame数据，一帧一帧的读取
        AVPacket temp;
        temp = *packet;
        if (packet->stream_index == video_stream_index) {
            video_queue->push(temp);
        } else if(packet->stream_index==audio_stream_index){
            audio_queue->push(temp);
        }
        usleep(6000);
    }

    isPlaying = false;
    delete video_queue;
    delete audio_queue;
    av_free_packet(packet);
    av_frame_free(&video->frame);
    av_frame_free(&audio->frame);
    av_free(audio->out_buffer);

    swr_free(&audio->swrCtx);
    avcodec_close(audio->codecCtx);
    avformat_close_input(&fmtCtx);

    av_frame_free(&video->scale_frame);
    avcodec_close(video->codecCtx);
    avformat_free_context(fmtCtx);
}


